package com.magold.circuit;

import java.util.LinkedList;
import java.util.List;

import com.magold.algorithm.MagoldMath;
import com.magold.circuit.module.CircuitModule;
import com.magold.circuit.state.CircuitState;

class CircuitPath implements ICircuitPath {
	private CircuitModule mPathBattery;
	private CircuitState mCurrentState;
	private Circuit mCircuit;
	private LinkedList<CircuitModule> mModules;
	private LinkedList<PathStateListener> mListeners;
	
	public CircuitPath(CircuitModule pBattery) {
		mPathBattery = pBattery;
		mModules = new LinkedList<CircuitModule>();
		mCurrentState = null;
	}
	
	public CircuitPath(CircuitPath pSharedModulesPath) {
		mPathBattery = pSharedModulesPath.mPathBattery;
		mModules = new LinkedList<CircuitModule>(pSharedModulesPath.mModules);
	}
	
	CircuitState computeState() {
		if (mPathBattery == null || !mPathBattery.isConnected()) {
			return setState(CircuitState.NO_POWER);
		}
		
		if (mModules.size() == 0) return setState(CircuitState.SHORT_CIRCUIT);
		
		for (CircuitModule module : mModules) {
			if (!module.isConnected()) {
				return setState(CircuitState.BREAKING);
			}
		}
		
		return setState(CircuitState.RUNNING);
	}
	
	protected CircuitState setState(CircuitState pState) {
		CircuitState prev = mCurrentState;
		mCurrentState = pState;
		if (MagoldMath.onlyOneEquals(CircuitState.RUNNING, prev, mCurrentState)) {
			fireStateChanged(prev);
		}
		return pState;
	}

	protected void fireStateChanged(CircuitState pPrevState) {
		if (mListeners == null) return;
		
		switch (mCurrentState) {
		case RUNNING:
			for (PathStateListener listener : mListeners) {
				listener.onPathConnected(this);
			}
			break;
		case BREAKING:
			for (PathStateListener listener : mListeners) {
				listener.onPathDisconnected(this);
			}
			break;
		case SHORT_CIRCUIT:
			for (PathStateListener listener : mListeners) {
				listener.onPathShortCutted(this);
			}
			break;
		case NO_POWER:
			for (PathStateListener listener : mListeners) {
				listener.onPathPowerOff(this);
			}
			break;
		}
	}

	boolean addModule(CircuitModule pModule) {
		if (pModule == null) return false;
		if (mModules.add(pModule)) {
			pModule.onPathJoined(mCircuit, this);
			return true;
		}
		
		return false;
	}
	
	@Override
	public CircuitModule getNextModule(CircuitModule pCurrent) {
		if (mModules.size() == 0) return null;
		if (pCurrent == mPathBattery) {
			return mModules.get(0);
		}
		
		int idx = mModules.indexOf(pCurrent) + 1;
		if (idx == mModules.size()) {
			return mPathBattery;
		}
		
		return mModules.get(idx);
	}
	
	@Override
	public CircuitModule getPrevModule(CircuitModule pCurrent) {
		if (mModules.size() == 0) return null;
		if (pCurrent == mPathBattery) {
			return mModules.getLast();
		}
		
		int idx = mModules.indexOf(pCurrent) - 1;
		if (idx == -1) {
			return mPathBattery;
		}
		
		return mModules.get(idx);
	}

	@Override
	public CircuitModule getBattery() {
		return mPathBattery;
	}

	@Override
	public CircuitState getCurrentState() {
		return mCurrentState;
	}

	@Override
	public void registerListener(PathStateListener pListener) {
		if (pListener == null) return;
		
		if (mListeners == null) {
			mListeners = new LinkedList<PathStateListener>();
		}
		
		mListeners.add(pListener);
	}

	@Override
	public void removeListener(PathStateListener pListener) {
		if (mListeners != null) {
			mListeners.remove(pListener);
		}
	}
	
	void setCircuit(Circuit pCircuit) {
		mCircuit = pCircuit;
	}
	
	@Override
	public Circuit getCircuit() {
		return mCircuit;
	}
	
	List<CircuitModule> getModules() {
		return mModules;
	}
}